#include "stdafx.h"

#include "hwintext.h"

namespace harlinn
{
    namespace windows
    {
        namespace text
        {
            HWIN_EXPORT StringBuilder::DataManager StringBuilder::dataManager;

            HWIN_EXPORT StringBuilder::DataManager::DataManager()
            {
                for(unsigned i = 0; i < cacheSize; i++)
                {
                    cache[i] = nullptr;
                }
                InitializeCriticalSection(&mutex);
            }
            HWIN_EXPORT StringBuilder::DataManager::~DataManager()
            {
                DeleteCriticalSection(&mutex);
            }
            HWIN_EXPORT StringBuilder::Data* StringBuilder::DataManager::Allocate(size_t minCapacity)
            {
                StringBuilder::Data* result = nullptr;
                if(minCapacity > DataBlockTextSize)
                {
                    result = new StringBuilder::Data(minCapacity);
                }
                else
                {
                    
                    EnterCriticalSection(&mutex);

                    for(unsigned i = 0; i < cacheSize; i++)
                    {
                        result = cache[i];
                        if(result)
                        {
                            cache[i] = nullptr;
                            break;
                        }
                    }

                    LeaveCriticalSection(&mutex);
                    if(!result)
                    {
                        result = new StringBuilder::Data(1);
                    }
                    else
                    {
                        result->Reset();
                    }
                    
                }
                return result;
            }
            HWIN_EXPORT void StringBuilder::DataManager::Free(StringBuilder::Data* data)
            {
                if(data->start && data->start == data->end)
                {
                    bool added = false;
                    EnterCriticalSection(&mutex);
                    for(unsigned i = 0; i < cacheSize; i++)
                    {
                        if(cache[i] == nullptr)
                        {
                            cache[i] = data;
                            added = true;
                        }
                    }
                    LeaveCriticalSection(&mutex);
                    if(added)
                    {
                        return;
                    }
                }
                delete data;
            }

            // -----------------------------------------------------------------
            // Endoding
            // -----------------------------------------------------------------
            HWIN_EXPORT std::shared_ptr<Endoding> Endoding::ASCII = std::make_shared<Endoding>(20127); // us-7-bit ascii
            HWIN_EXPORT std::shared_ptr<Endoding> Endoding::UTF8 = std::make_shared<Endoding>(65001); 
            HWIN_EXPORT std::shared_ptr<Endoding> Endoding::UTF7 = std::make_shared<Endoding>(65000);
            HWIN_EXPORT std::shared_ptr<Endoding> Endoding::Latin1 = std::make_shared<Endoding>(1252);

            HWIN_EXPORT Endoding::Endoding()
                : codePage(CP_ACP)
            {
            }
            HWIN_EXPORT Endoding::Endoding(unsigned theCodePage)
                : codePage(theCodePage)
            {
            }

            HWIN_EXPORT String Endoding::GetString( const std::vector<Byte::ValueType>& bytes )
            {
                wchar_t buffer[128];
                LPCSTR pMbData = (LPCSTR)bytes.data();
                int mbLength = int(bytes.size());
                if(mbLength)
                {
                    auto length = MultiByteToWideChar(codePage,MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,pMbData,mbLength,buffer,128);
                    if(!length)
                    {
                        auto lastError = GetLastError();
                        if(lastError != ERROR_INSUFFICIENT_BUFFER)
                        {
                            ThrowLastOSError();
                        }
                        length = MultiByteToWideChar(codePage,MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,pMbData,mbLength,nullptr,0);
                        String result;
                        result.SetLength(length);
                        length = MultiByteToWideChar(codePage,MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,pMbData,mbLength,result.c_str(),length);
                        return result;
                    }
                    String result(buffer,String::size_type(length));
                    return result;
                }
                return String();
            }

            HWIN_EXPORT std::shared_ptr< std::vector<Byte::ValueType> > Endoding::GetBytes( const String& theText )
            {
                auto result = std::make_shared< std::vector<Byte::ValueType> >();
                int textLength = int(theText.length());
                if(textLength)
                {
                    LPCWSTR pText = theText.c_str();
                    auto length = WideCharToMultiByte(codePage,0,pText,textLength,nullptr,0,nullptr,nullptr);
                    if(length == 0)
                    {
                        ThrowLastOSError();
                    }
                    result->resize(length);
                    LPSTR pResultData = (LPSTR)result->data();
                    WideCharToMultiByte(codePage,0,pText,textLength,pResultData,length,nullptr,nullptr);
                }
                return result;
            }

        };
    };
};